iT邦幫忙

2022 iThome 鐵人賽

DAY 8
0
Mobile Development

android studio 30天 精華筆記系列 第 8

精華筆記 Day8--拍照存檔和照片讀檔

  • 分享至 

  • xImage
  •  

今天來講點與手機相機互動的方法,先在雖然這種做法比較不常見,但這種互動的概念還是很值得提一下的。
還又今天的程式碼比較特別是用Kotlin的,畢竟是寫安卓,Kotlin身為android開發語言的一員,了解一下也是無訪,席官Java的同學不用太擔心,今天的程式不會和Java差上太多。

  1. 設計UI
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/imagePicker_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="選擇照片"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/guideline2"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/guideline3" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.50" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.80" />

    <Button
        android:id="@+id/camera_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="4dp"
        android:text="拍照"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="@+id/guideline2"
        app:layout_constraintTop_toTopOf="@+id/guideline3" />

    <ImageView
        android:id="@+id/picture_img"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@+id/guideline4"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/guideline7" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.5" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.11" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline6"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.9" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline7"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.02872777" />

    <Button
        android:id="@+id/save_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="儲存"
        app:layout_constraintBottom_toTopOf="@+id/guideline3"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/guideline4" />

</androidx.constraintlayout.widget.ConstraintLayout>

ImageView用來顯示拍照結果和顯示圖片讀取結果。
2. 實例化和啟動相機及選擇檔案管理

lateinit var imagePicker_btn:Button
lateinit var camera_btn:Button
override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        imagePicker_btn = findViewById(R.id.imagePicker_btn)
        camera_btn = findViewById(R.id.camera_btn)
        picture_img = findViewById(R.id.picture_img)

        imagePicker_btn.setOnClickListener(View.OnClickListener {
            //開啟檔案管理Intent.ACTION_PICK
            val intent = Intent(Intent.ACTION_PICK)
            intent.type = "image/*"
            imagePickerLauncher.launch(intent)

        })

        camera_btn.setOnClickListener(View.OnClickListener {
            //開啟相機
            val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
            cameraLauncher.launch(intent)
        })
}
  1. 註冊回調

因為選擇圖片和開啟相機都將離開此app,稍後才帶結果返回。

//圖片選擇的回調
private val imagePickerLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { activityResult ->
        if (RESULT_OK == activityResult.resultCode) {
            val resolver = this.contentResolver
            //將選擇的照片轉成Bitmap
            bitmap = MediaStore.Images.Media.getBitmap(resolver, activityResult.data?.data)
            //imageView顯示結果
            picture_img.setImageBitmap(bitmap)
        }
    }
//照相機拍照後的回調    
private val cameraLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){result ->
        if(RESULT_OK == result.resultCode) {
            //將拍攝的照片轉成Bitmap,透過"data"獲得
            bitmap = result.data?.extras?.get("data") as Bitmap
            //imageView顯示結果
            picture_img.setImageBitmap(bitmap)
        }
    }

此方法如同比較常見的onActivityResult,不過onActivityResult已被棄用,但作用是差不多的,使用onActivityResult也是可以達到此效果的。
3. 儲存按鈕

lateinit var save_btn:Button

override fun onCreate(savedInstanceState: Bundle?) {
    ...
    save_btn = findViewById(R.id.save_btn)
    save_btn.setOnClickListener(View.OnClickListener {
        try {
            //檔名
            val fileName:String = System.currentTimeMillis().toString()+".jpg"
            // 新增資料夾Camera,並尋找fileName
            val file =File(Environment.getExternalStoragePublicDirectory(
                                  Environment.DIRECTORY_DCIM).path+"/Camera/",fileName)
            //輸出流                      
            val out = FileOutputStream(file)
            bitmap.compress(Bitmap.CompressFormat.JPEG,100,out)
            out.flush()
            //關閉輸出流
            out.close()

            //通知其掃描新建的圖片檔案,這樣新拍的照片儲存後才找的到
            val uri: Uri = Uri.fromFile(file)
            sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri))
            Toast.makeText(mContext,"儲存成功",Toast.LENGTH_SHORT).show()
        }catch (e:Exception){
            Toast.makeText(mContext,"儲存失敗",Toast.LENGTH_SHORT).show()
        }
    })
}

這樣就完成拍照和儲存的功能,要注意的是儲存的位置需要注意(能否讀取等),否則會看不到儲存的效果。

結果效果

拍照

https://ithelp.ithome.com.tw/upload/images/20220802/20139136qZrJCVtYpt.jpg

顯示照片

https://ithelp.ithome.com.tw/upload/images/20220802/201391360MfPMVxvig.jpg

照片讀取

https://ithelp.ithome.com.tw/upload/images/20220802/201391365SmcIiaAGF.jpg

今天就先講解到這邊,主要是希望各位能知道如何與其他程式互動,並接受回傳的資料。(重點知識:registerForActivityResult和onActivityResult可以去研究一下喔!)


上一篇
精華筆記 Day7--File 讀/寫/刪
下一篇
精華筆記 Day9--多國語系
系列文
android studio 30天 精華筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言